﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Runtime.InteropServices;

namespace UISockets
{
    class CTILinker
    {
        private Socket workSocket = null;
        private string ctiHost = "127.0.0.1";
        private int ctiPort = 6853;

        private struct PackStateObject
        {
            public int bytesRead;//记录在recvBuffer中已经接收了多少数据
            public byte[] recvBuffer;//提供给BeginRecv的Buffer
            public ManualResetEvent recvFinishFlag;
        }

        public void SetCTIAddress(string host, int port)
        {
            if (ctiHost != host || ctiPort != port)
            {
                if (workSocket != null)
                {
                    Close();
                }
                ctiHost = host;
                ctiPort = port;
            }
        }

        public void Close()
        {
            if (workSocket != null)
            {
                if (workSocket.Connected)
                {
                    workSocket.Shutdown(SocketShutdown.Both); //不确定在异步状态下，该方法是否会关掉所有的Send和Recv所开启的线程
                }
                workSocket.Close();
            }
        }

        #region 连接CTI
        private ManualResetEvent connectDone = new ManualResetEvent(false);
        public void Connect()
        {
            workSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPAddress ip = IPAddress.Parse(ctiHost);
            IPEndPoint iep = new IPEndPoint(ip, ctiPort);
            workSocket.BeginConnect(iep, new AsyncCallback(DoConnect), workSocket);
            connectDone.WaitOne();
        }

        private void DoConnect(IAsyncResult iar)
        {
            try
            {
                workSocket.EndConnect(iar);

                Console.WriteLine("Connect CTI({0}) success.",
                    workSocket.RemoteEndPoint.ToString());

                Console.WriteLine("Start send key pack to CTI.");
                SendKeyPack();
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
            finally
            {
            }
            connectDone.Set();
        }
        #endregion

        #region 发送数据接口
        public void Send(byte[] data)
        {
            if (workSocket == null || !workSocket.Connected)
            {
                Connect();
            }

            if (workSocket.Connected)
            {
                try
                {
                    // Begin sending the data to the remote device.
                    workSocket.BeginSend(data, 0, data.Length, 0,
                            new AsyncCallback(SendCallback), workSocket);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.ToString());
                }
                finally
                {
                }
            }
        }
        private void SendCallback(IAsyncResult iar)
        {
        }
        #endregion 

        #region 接收数据接口

        //开启数据接收流程
        public void StartWaitForData()
        {
            //开始进行数据接收流程
            StartReceivePackHead();
        }
        

        private void StartReceivePackHead()
        {
            if (workSocket == null || !workSocket.Connected)
            {
                Connect();
            }

            if (!workSocket.Connected)
            {
                return;
            }

            try
            {
                PackStateObject packHeadState = new PackStateObject();
                packHeadState.bytesRead = 0;
                packHeadState.recvBuffer = new byte[CTIMsg.PACK_HEAD.packHeadSize];

                // Begin receiving the data from the remote device.
                workSocket.BeginReceive(packHeadState.recvBuffer, 0, packHeadState.recvBuffer.Length, 0,
                    new AsyncCallback(PackHeadReceiveCallback), packHeadState);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
            finally
            {
            }
        }

        private void PackHeadReceiveCallback(IAsyncResult ar)
        {
            PackStateObject packHeadState = (PackStateObject)ar.AsyncState;
            int bytesRead = workSocket.EndReceive(ar);
            packHeadState.bytesRead += bytesRead;//增加计数

            if (packHeadState.bytesRead < packHeadState.recvBuffer.Length)
            {
                //当实际收到的数据包的大小， 小于需要接收的数据包大小, 那就需要再次调用接收剩下的数据
                workSocket.BeginReceive(packHeadState.recvBuffer, packHeadState.bytesRead, packHeadState.recvBuffer.Length - packHeadState.bytesRead, 0,
    new AsyncCallback(PackHeadReceiveCallback), packHeadState);
            }
            else if (packHeadState.bytesRead == packHeadState.recvBuffer.Length)
            {
                //实际接收的数据等于需要接收的数据
                //开始接收剩下的数据包

                //将byte[] 转为struct
                CTIMsg.PACK_HEAD packHead = (CTIMsg.PACK_HEAD)CTIMsg.BytesToStruct(packHeadState.recvBuffer, typeof(CTIMsg.PACK_HEAD));

                Console.WriteLine("Pack Head msgID={0} msgSize={1}.", packHead.id, packHead.size);

                ReceiveTheRestPack(packHead);
            }
            else
            {
                //实际接收的数据大于需要接收的数据，  报错了
                Console.WriteLine("error");
            }
        }

        private void ReceiveTheRestPack(CTIMsg.PACK_HEAD packHead)
        {
            //接收该消息报中剩下的数据
            byte[] data = ReceivePack(packHead);

            switch (packHead.id)
            {
                case CTIMsg.PACK_RESP_CONNECT_SUCCESS.ID:
                    Console.WriteLine("Receive connect success response from cti.");
                    break;

                case CTIMsg.PACK_RESP_LINK_EXIST.ID:
                    Console.WriteLine("Receive connect fail response from cti.");
                    break;

                case CTIMsg.PACK_RESP_DRIVER_INFO_LIST.ID:
                    {
                        int nextStructBegin = 0;
                        CTIMsg.PACK_RESP_DRIVER_INFO_LIST respStruct = (CTIMsg.PACK_RESP_DRIVER_INFO_LIST)CTIMsg.BytesToStruct(data, nextStructBegin, typeof(CTIMsg.PACK_RESP_DRIVER_INFO_LIST));
                        nextStructBegin += CTIMsg.PACK_RESP_DRIVER_INFO_LIST.packSize;

                        Console.WriteLine("Receive driver config list from cti.");
                        for (int i = 0; i < respStruct.driverCount; ++i )
                        {
                            Console.Write("{0}:", i);

                            Tuple<object, String, int>  tupleDriverInfo= CTIMsg.BytesToVariableLengthStruct(data, nextStructBegin, typeof(CTIMsg.DRIVER_INFO));
                            nextStructBegin += tupleDriverInfo.Item3;

                            CTIMsg.DRIVER_INFO driverInfoStruct = (CTIMsg.DRIVER_INFO)tupleDriverInfo.Item1;


                            String driverName = CTIMsg.NulltTerminatedAsciiBytesToString(driverInfoStruct.driverName);
                            String dllFileName = CTIMsg.NulltTerminatedAsciiBytesToString(driverInfoStruct.dllFileName);
                            String errorStr = CTIMsg.NulltTerminatedAsciiBytesToString(driverInfoStruct.errStr);
                            String driverInfo = tupleDriverInfo.Item2;

                            Console.WriteLine("driverName:{0}, filename:{1}, errorStr:{2}, driverInfo:{3}."
                                , driverName
                                , dllFileName
                                , errorStr
                                , driverInfo);
                        }
                    }
                    break;

                case CTIMsg.PACK_RESP_DRIVER_INFO_BY_DRIVERNAME.ID:
                    {
                        Console.WriteLine("Receive driver info by driver name response from cti.");
                        Tuple<object, String, int> tupleDriverInfo = CTIMsg.BytesToVariableLengthStruct(data, 0, typeof(CTIMsg.PACK_RESP_DRIVER_INFO_BY_DRIVERNAME));

                        CTIMsg.PACK_RESP_DRIVER_INFO_BY_DRIVERNAME respDriverInfo = (CTIMsg.PACK_RESP_DRIVER_INFO_BY_DRIVERNAME)tupleDriverInfo.Item1;


                        String errStr = CTIMsg.NulltTerminatedAsciiBytesToString(respDriverInfo.errStr);
                        String driverName = CTIMsg.NulltTerminatedAsciiBytesToString(respDriverInfo.driverName);
                        String driverInfo = tupleDriverInfo.Item2;

                        Console.WriteLine("driverName:{0}, errStr:{1}, driverInfo:{2}."
                        , driverName
                        , errStr
                        , driverInfo);
                    }
                    break;

                case CTIMsg.PACK_RESP_DRIVER_INFO_BY_DLLNAME.ID:
                    {
                        Console.WriteLine("Receive driver info by dll name response from cti.");
                        Tuple<object, String, int> tupleDriverInfo = CTIMsg.BytesToVariableLengthStruct(data, 0, typeof(CTIMsg.PACK_RESP_DRIVER_INFO_BY_DLLNAME));

                        CTIMsg.PACK_RESP_DRIVER_INFO_BY_DLLNAME respDriverInfo = (CTIMsg.PACK_RESP_DRIVER_INFO_BY_DLLNAME)tupleDriverInfo.Item1;


                        String errStr = CTIMsg.NulltTerminatedAsciiBytesToString(respDriverInfo.errStr);
                        String dllFileName = CTIMsg.NulltTerminatedAsciiBytesToString(respDriverInfo.dllFileName);
                        String driverInfo = tupleDriverInfo.Item2;

                        Console.WriteLine("dllFileName:{0}, errStr:{1}, driverInfo:{2}."
                        , dllFileName
                        , errStr
                        , driverInfo);
                    }
                    break;

                case CTIMsg.PACK_RESP_ADD_DRIVER.ID:
                    {
                        Console.WriteLine("Receive add driver response from cti.");
                        CTIMsg.PACK_RESP_ADD_DRIVER respStruct = (CTIMsg.PACK_RESP_ADD_DRIVER)CTIMsg.BytesToStruct(data, typeof(CTIMsg.PACK_RESP_ADD_DRIVER));

                        String errStr = CTIMsg.NulltTerminatedAsciiBytesToString(respStruct.errStr);
                        String driverName = CTIMsg.NulltTerminatedAsciiBytesToString(respStruct.driverName);

                        Console.WriteLine("driverName:{0}, errStr:{1}."
                        , driverName
                        , errStr
                        );
                    }
                    break;

                case CTIMsg.PACK_RESP_UPDATE_DRIVER.ID:
                    {
                        Console.WriteLine("Receive update driver response from cti.");
                        CTIMsg.PACK_RESP_UPDATE_DRIVER respStruct = (CTIMsg.PACK_RESP_UPDATE_DRIVER)CTIMsg.BytesToStruct(data, typeof(CTIMsg.PACK_RESP_UPDATE_DRIVER));

                        String errStr = CTIMsg.NulltTerminatedAsciiBytesToString(respStruct.errStr);
                        String driverName = CTIMsg.NulltTerminatedAsciiBytesToString(respStruct.driverName);

                        Console.WriteLine("driverName:{0}, errStr:{1}."
                        , driverName
                        , errStr
                        );
                    }
                    break;

                case CTIMsg.PACK_RESP_DELETE_DRIVER.ID:
                    {
                        Console.WriteLine("Receive delete driver response from cti.");
                        CTIMsg.PACK_RESP_DELETE_DRIVER respStruct = (CTIMsg.PACK_RESP_DELETE_DRIVER)CTIMsg.BytesToStruct(data, typeof(CTIMsg.PACK_RESP_DELETE_DRIVER));

                        String errStr = CTIMsg.NulltTerminatedAsciiBytesToString(respStruct.errStr);
                        String driverName = CTIMsg.NulltTerminatedAsciiBytesToString(respStruct.driverName);

                        Console.WriteLine("driverName:{0}, errStr:{1}."
                        , driverName
                        , errStr
                        );
                    }
                    break;

                case CTIMsg.PACK_RESP_START_DRIVER.ID:
                    {
                        Console.WriteLine("Receive start driver response from cti.");
                        CTIMsg.PACK_RESP_START_DRIVER respStruct = (CTIMsg.PACK_RESP_START_DRIVER)CTIMsg.BytesToStruct(data, typeof(CTIMsg.PACK_RESP_START_DRIVER));

                        String errStr = CTIMsg.NulltTerminatedAsciiBytesToString(respStruct.errStr);
                        String driverName = CTIMsg.NulltTerminatedAsciiBytesToString(respStruct.driverName);

                        Console.WriteLine("driverName:{0}, errStr:{1}."
                        , driverName
                        , errStr
                        );
                    }
                    break;

                case CTIMsg.PACK_RESP_STOP_DRIVER.ID:
                    {
                        Console.WriteLine("Receive stop driver response from cti.");
                        CTIMsg.PACK_RESP_STOP_DRIVER respStruct = (CTIMsg.PACK_RESP_STOP_DRIVER)CTIMsg.BytesToStruct(data, typeof(CTIMsg.PACK_RESP_STOP_DRIVER));

                        String errStr = CTIMsg.NulltTerminatedAsciiBytesToString(respStruct.errStr);
                        String driverName = CTIMsg.NulltTerminatedAsciiBytesToString(respStruct.driverName);

                        Console.WriteLine("driverName:{0}, errStr:{1}."
                        , driverName
                        , errStr
                        );
                    }
                    break;

                case CTIMsg.PACK_RESP_CONTROLLER_COMMAND.ID:
                    {
                        Console.WriteLine("Receive controller msg  from cti.");
                        Tuple<object, String, int> controllerMsgTuple = CTIMsg.BytesToVariableLengthStruct(data, 0, typeof(CTIMsg.PACK_RESP_CONTROLLER_COMMAND));

                        CTIMsg.PACK_RESP_CONTROLLER_COMMAND controllerMsg = (CTIMsg.PACK_RESP_CONTROLLER_COMMAND)controllerMsgTuple.Item1;
                        String msgContent = controllerMsgTuple.Item2;

                        String msgType = "Unknown";
                        switch (controllerMsg.constoller_head.id)
                        {
                            case CTIMsg.CONTROLLER_RESP_LOG.ID:
                                msgType = "Log";
                                break;
                            case CTIMsg.CONTROLLER_RESP_LINE_STATUS_FIELDS.ID:
                                msgType = "Line Fields";
                                break;
                            case CTIMsg.CONTROLLER_RESP_LINE_STATUS_ADD.ID:
                                msgType = "Add Line";
                                break;
                            case CTIMsg.CONTROLLER_RESP_LINE_STATUS_CHANGE.ID:
                                msgType = "Change Line";
                                break;
                            case CTIMsg.CONTROLLER_RESP_LINE_STATUS_DELETE.ID:
                                msgType = "Delete Line";
                                break;
                            default:
                                break;
                        }

                        Console.WriteLine("{0} : {1}."
                        , msgType
                        , msgContent
                        );

                    }
                    break;

                default:
                    break;
            }

            Console.WriteLine("");

            //接收完成一个完整的消息包之后开始等待接收下一个完整的消息包
            StartReceivePackHead();
        }

        //接收指定大小的byte array
        private byte[] ReceivePack(CTIMsg.PACK_HEAD packHead)
        {
            int restPackSize = (int)packHead.size - CTIMsg.PACK_HEAD.packHeadSize; //计算出剩下需要接收的数据包的大小
            if (restPackSize == 0)
            {
                return null;
            }

            PackStateObject packState = new PackStateObject();
            try
            {
                packState.bytesRead = (int)CTIMsg.PACK_HEAD.packHeadSize; //已经接收了包头大小的数据包
                packState.recvBuffer = new byte[packHead.size];
                packState.recvFinishFlag = new ManualResetEvent(false);

                //将包头拷贝到前面
                CTIMsg.StructToBytes(packHead).CopyTo(packState.recvBuffer, 0);

                // Begin receiving the data from the remote device.
                workSocket.BeginReceive(packState.recvBuffer, packState.bytesRead, restPackSize, 0,
                    new AsyncCallback(ReceivePackCallBack), packState);

                packState.recvFinishFlag.WaitOne();
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
            finally
            {
            }
            return packState.recvBuffer;
        }

        //接收指定大小的数据包回调
        private void ReceivePackCallBack(IAsyncResult ar)
        {
            PackStateObject packState = (PackStateObject)ar.AsyncState;
            int bytesRead = workSocket.EndReceive(ar);
            packState.bytesRead += bytesRead;//增加计数

            if (packState.bytesRead < packState.recvBuffer.Length)
            {
                //当实际收到的数据包的大小， 小于需要接收的数据包大小, 那就需要再次调用接收剩下的数据
                workSocket.BeginReceive(packState.recvBuffer, packState.bytesRead, packState.recvBuffer.Length - packState.bytesRead, 0,
    new AsyncCallback(ReceivePackCallBack), packState);
            }
            else if (packState.bytesRead == packState.recvBuffer.Length)
            {
                //实际接收的数据等于需要接收的数据
                //接收完毕 返回
                packState.recvFinishFlag.Set();
            }
            else
            {
                //实际接收的数据大于需要接收的数据，  报错了
                Console.WriteLine("error");
            }
        }
        #endregion


        #region UI请求发送接口

        //Key包直接在连接成功之后立刻发送
        private void SendKeyPack()
        {
            CTIMsg.PACK_STREAM_SOCKET_KEY keyPack = new CTIMsg.PACK_STREAM_SOCKET_KEY();
            keyPack.head.id = CTIMsg.PACK_STREAM_SOCKET_KEY.ID;
            keyPack.head.size = unchecked((uint)CTIMsg.PACK_STREAM_SOCKET_KEY.packSize);
            keyPack.key = CTIMsg.GUID_KEY_UICOMMAND;

            Send( CTIMsg.StructToBytes(keyPack) );
        }

        public void SendRequestGetDriverInfoList()
        {

            Console.WriteLine("Send request driver info list to cti.");

            CTIMsg.PACK_REQU_GET_DRIVER_INFO_LIST request = new CTIMsg.PACK_REQU_GET_DRIVER_INFO_LIST();
            request.head.id = CTIMsg.PACK_REQU_GET_DRIVER_INFO_LIST.ID;
            request.head.size = unchecked((uint)CTIMsg.PACK_REQU_GET_DRIVER_INFO_LIST.packSize);

            Send(CTIMsg.StructToBytes(request));
        }


        public void SendRequestDriverInfoByDriverName(String driverName)
        {
            Console.WriteLine("Send request driver info by driver name({0}).", driverName);

            CTIMsg.PACK_REQU_DRIVER_INFO_BY_DRIVERNAME request = new CTIMsg.PACK_REQU_DRIVER_INFO_BY_DRIVERNAME();
            request.head.id = CTIMsg.PACK_REQU_DRIVER_INFO_BY_DRIVERNAME.ID;
            request.head.size = unchecked((uint)CTIMsg.PACK_REQU_DRIVER_INFO_BY_DRIVERNAME.packSize);

            request.driverName = new byte[CTIMsg.MAX_DRIVER_NAME];
            byte[] bDriverName= Encoding.ASCII.GetBytes(driverName);
            Array.Copy(bDriverName, request.driverName, bDriverName.Length);

            Send(CTIMsg.StructToBytes(request));
        }

        public void SendRequestDriverInfoByDLLName(String dllFileName)
        {
            Console.WriteLine("Send request driver info by dll name({0}).", dllFileName);

            CTIMsg.PACK_REQU_DRIVER_INFO_BY_DLLNAME request = new CTIMsg.PACK_REQU_DRIVER_INFO_BY_DLLNAME();
            request.head.id = CTIMsg.PACK_REQU_DRIVER_INFO_BY_DLLNAME.ID;
            request.head.size = unchecked((uint)CTIMsg.PACK_REQU_DRIVER_INFO_BY_DLLNAME.packSize);

            request.dllFileName = new byte[CTIMsg.MAX_PATH];
            byte[] bFileName = Encoding.ASCII.GetBytes(dllFileName);
            Array.Copy(bFileName, request.dllFileName, bFileName.Length);

            Send(CTIMsg.StructToBytes(request));
        }

        public void SendRequestAddDriver(String driverName, String dllFileName, String driverConfig)
        {
            Console.WriteLine("Send request add driver, driverName={0}, dllFileName={1}, driverParam={2}.", driverName, dllFileName, driverConfig);

            CTIMsg.PACK_REQU_ADD_DRIVER request = new CTIMsg.PACK_REQU_ADD_DRIVER();
            request.head.id = CTIMsg.PACK_REQU_ADD_DRIVER.ID;
            request.head.size = unchecked((uint)CTIMsg.PACK_REQU_ADD_DRIVER.packSize);

            request.driverConfig = new CTIMsg.DRIVER_CONFIG();
            request.driverConfig.structSize = unchecked((uint)CTIMsg.DRIVER_CONFIG.size);

            request.driverConfig.driverName = new byte[CTIMsg.MAX_DRIVER_NAME];
            byte[] bTemp = Encoding.ASCII.GetBytes(driverName);
            Array.Copy(bTemp, request.driverConfig.driverName, bTemp.Length);

            request.driverConfig.dllFileName = new byte[CTIMsg.MAX_PATH];
            bTemp = Encoding.ASCII.GetBytes(dllFileName);
            Array.Copy(bTemp, request.driverConfig.dllFileName, bTemp.Length);

            //结构体中的变长字符串, 修正结构体的大小
            byte[] varString = Encoding.ASCII.GetBytes(driverConfig);
            request.head.size += unchecked((uint)varString.Length);
            request.driverConfig.structSize += unchecked((uint)varString.Length);


            Send(CTIMsg.VariableLengthStructToBytes(request, varString));
        }

        public void SendRequestUpdateDriver(String driverName, String dllFileName, String driverConfig)
        {
            Console.WriteLine("Send request update driver, driverName={0}, dllFileName={1}, driverConfig={2}.", driverName, dllFileName, driverConfig);

            CTIMsg.PACK_REQU_UPDATE_DRIVER request = new CTIMsg.PACK_REQU_UPDATE_DRIVER();
            request.head.id = CTIMsg.PACK_REQU_UPDATE_DRIVER.ID;
            request.head.size = unchecked((uint)CTIMsg.PACK_REQU_UPDATE_DRIVER.packSize);


            request.driverName = new byte[CTIMsg.MAX_DRIVER_NAME];
            byte[] bTemp = Encoding.ASCII.GetBytes(driverName);
            Array.Copy(bTemp, request.driverName, bTemp.Length);

            //结构体中的变长字符串, 修正结构体的大小
            byte[] varString = Encoding.ASCII.GetBytes(driverConfig);
            request.head.size += unchecked((uint)varString.Length);

            Send(CTIMsg.VariableLengthStructToBytes(request, varString));
        }

        public void SendRequestDeleteDriver(String driverName)
        {
            Console.WriteLine("Send request delete driver, driverName={0}.", driverName);

            CTIMsg.PACK_REQU_DELETE_DRIVER request = new CTIMsg.PACK_REQU_DELETE_DRIVER();
            request.head.id = CTIMsg.PACK_REQU_DELETE_DRIVER.ID;
            request.head.size = unchecked((uint)CTIMsg.PACK_REQU_DELETE_DRIVER.packSize);

            request.driverName = new byte[CTIMsg.MAX_DRIVER_NAME];
            byte[] bTemp = Encoding.ASCII.GetBytes(driverName);
            Array.Copy(bTemp, request.driverName, bTemp.Length);

            Send(CTIMsg.StructToBytes(request));
        }

        public void SendRequestStartDriver(String driverName)
        {
            Console.WriteLine("Send request start driver, driverName={0}.", driverName);
            CTIMsg.PACK_REQU_START_DRIVER request = new CTIMsg.PACK_REQU_START_DRIVER();
            request.head.id = CTIMsg.PACK_REQU_START_DRIVER.ID;
            request.head.size = unchecked((uint)CTIMsg.PACK_REQU_START_DRIVER.packSize);

            request.driverName = new byte[CTIMsg.MAX_DRIVER_NAME];
            byte[] bTemp = Encoding.ASCII.GetBytes(driverName);
            Array.Copy(bTemp, request.driverName, bTemp.Length);

            Send(CTIMsg.StructToBytes(request));
        }


        public void SendRequestStopDriver(String driverName)
        {
            Console.WriteLine("Send request stop driver, driverName={0}.", driverName);
            CTIMsg.PACK_REQU_STOP_DRIVER request = new CTIMsg.PACK_REQU_STOP_DRIVER();
            request.head.id = CTIMsg.PACK_REQU_STOP_DRIVER.ID;
            request.head.size = unchecked((uint)CTIMsg.PACK_REQU_STOP_DRIVER.packSize);

            request.driverName = new byte[CTIMsg.MAX_DRIVER_NAME];
            byte[] bTemp = Encoding.ASCII.GetBytes(driverName);
            Array.Copy(bTemp, request.driverName, bTemp.Length);

            Send(CTIMsg.StructToBytes(request));
        }


        public void SendRequestStartLog()
        {
            Console.WriteLine("Send request start log to controller.");

            CTIMsg.PACK_REQU_CONTROLLER_COMMAND request = new CTIMsg.PACK_REQU_CONTROLLER_COMMAND();
            request.head.id = CTIMsg.PACK_REQU_CONTROLLER_COMMAND.ID;
            request.head.size = unchecked((uint)CTIMsg.PACK_REQU_CONTROLLER_COMMAND.packSize);

            CTIMsg.REQU_CONTROLLER_OPEN_LOG openLog = new CTIMsg.REQU_CONTROLLER_OPEN_LOG();
            openLog.head.id = CTIMsg.REQU_CONTROLLER_OPEN_LOG.ID;
            openLog.head.size = unchecked((uint)CTIMsg.REQU_CONTROLLER_OPEN_LOG.packSize);

            //修正大小
            request.head.size += openLog.head.size;

            Send(CTIMsg.CombineStructsToBytes(request, openLog));
        }


        public void SendRequestStopLog()
        {
            Console.WriteLine("Send request stop log to controller.");

            CTIMsg.PACK_REQU_CONTROLLER_COMMAND request = new CTIMsg.PACK_REQU_CONTROLLER_COMMAND();
            request.head.id = CTIMsg.PACK_REQU_CONTROLLER_COMMAND.ID;
            request.head.size = unchecked((uint)CTIMsg.PACK_REQU_CONTROLLER_COMMAND.packSize);

            CTIMsg.REQU_CONTROLLER_CLOSE_LOG closeLog = new CTIMsg.REQU_CONTROLLER_CLOSE_LOG();
            closeLog.head.id = CTIMsg.REQU_CONTROLLER_CLOSE_LOG.ID;
            closeLog.head.size = unchecked((uint)CTIMsg.REQU_CONTROLLER_CLOSE_LOG.packSize);

            //修正大小
            request.head.size += closeLog.head.size;

            Send(CTIMsg.CombineStructsToBytes(request, closeLog));
        }


        public void SendRequestOpenLineInfo()
        {
            Console.WriteLine("Send request open line info to controller.");

            CTIMsg.PACK_REQU_CONTROLLER_COMMAND request = new CTIMsg.PACK_REQU_CONTROLLER_COMMAND();
            request.head.id = CTIMsg.PACK_REQU_CONTROLLER_COMMAND.ID;
            request.head.size = unchecked((uint)CTIMsg.PACK_REQU_CONTROLLER_COMMAND.packSize);

            CTIMsg.REQU_OPEN_LINE_STATUS openLineInfo = new CTIMsg.REQU_OPEN_LINE_STATUS();
            openLineInfo.head.id = CTIMsg.REQU_OPEN_LINE_STATUS.ID;
            openLineInfo.head.size = unchecked((uint)CTIMsg.REQU_OPEN_LINE_STATUS.packSize);

            //修正大小
            request.head.size += openLineInfo.head.size;

            Send(CTIMsg.CombineStructsToBytes(request, openLineInfo));
        }

        public void SendRequestCloseLineInfo()
        {
            Console.WriteLine("Send request close line info to controller.");


            CTIMsg.PACK_REQU_CONTROLLER_COMMAND request = new CTIMsg.PACK_REQU_CONTROLLER_COMMAND();
            request.head.id = CTIMsg.PACK_REQU_CONTROLLER_COMMAND.ID;
            request.head.size = unchecked((uint)CTIMsg.PACK_REQU_CONTROLLER_COMMAND.packSize);

            CTIMsg.REQU_CLOSE_LINE_STATUS closeLineInfo = new CTIMsg.REQU_CLOSE_LINE_STATUS();
            closeLineInfo.head.id = CTIMsg.REQU_CLOSE_LINE_STATUS.ID;
            closeLineInfo.head.size = unchecked((uint)CTIMsg.REQU_CLOSE_LINE_STATUS.packSize);

            //修正大小
            request.head.size += closeLineInfo.head.size;

            Send(CTIMsg.CombineStructsToBytes(request, closeLineInfo));
        }

        #endregion
    }
}
